﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Xierun.Models.Core;
using Z.EntityFramework.Plus;

namespace Xierun
{
    /// <summary>
    ///     单表业务，isSaveChange默认为true，要多表增删改，请设置为false
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseService<T> : IBaseService<T>where T : Entity, new()
    {
        #region 私有域

        private readonly EntityContext _context;
        private readonly DbSet<T> _dbSet;

        public BaseService(EntityContext context)
        {
            _context = context;
            _dbSet = context.Set<T>();
        }

        /// <summary>
        ///     无跟踪过滤
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        private IQueryable<T> Filter(Expression<Func<T, bool>> exp)
        {
            var dbSet = _context.Set<T>().AsNoTracking().AsQueryable();
            if (exp != null)
                dbSet = dbSet.Where(exp);
            return dbSet;
        }

        #endregion

        #region 查询

        /// <summary>
        ///     根据id查找单个实体，且不被上下文所跟踪
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T GetSingleById(string id)
        {
            return _context.Set<T>().AsNoTracking().FirstOrDefault(x => x.Id == id);
        }

        /// <summary>
        ///     根据id查找单个实体，且不被上下文所跟踪
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Task<T> GetSingleByIdAsync(string id)
        {
            return _context.Set<T>().AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
        }

        /// <summary>
        ///     根据查询条件查找单个实体，且不被上下文所跟踪
        /// </summary>
        public T GetSingle(Expression<Func<T, bool>> exp)
        {
            return _context.Set<T>().AsNoTracking().FirstOrDefault(exp);
        }

        /// <summary>
        ///     根据查询条件查找单个实体，且不被上下文所跟踪
        /// </summary>
        public async Task<T> GetSingleAsycn(Expression<Func<T, bool>> exp)
        {
            return await _context.Set<T>().AsNoTracking().FirstOrDefaultAsync(exp);
        }

        /// <summary>
        ///     根据过滤条件，默认全部，获取实体列表，无跟踪
        /// </summary>
        /// <param name="exp">The exp.</param>
        public List<T> GetList(Expression<Func<T, bool>> exp = null)
        {
            return Filter(exp).ToList();
        }

        /// <summary>
        ///     根据过滤条件，默认全部，获取实体列表，无跟踪
        /// </summary>
        /// <param name="exp">The exp.</param>
        public Task<List<T>> GetListAsync(Expression<Func<T, bool>> exp = null)
        {
            return Filter(exp).ToListAsync();
        }

        /// <summary>
        ///     根据分页信息得到分页记录，默认Id排序
        /// </summary>
        /// <param name="pageIndex">The pageindex.</param>
        /// <param name="pageSize">The pagesize.</param>
        /// <param name="orderBy">排序，格式如："Id"/"Id descending"</param>
        public List<T> GetList(int pageIndex, int pageSize, string orderBy = "", Expression<Func<T, bool>> exp = null)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (string.IsNullOrEmpty(orderBy))
                orderBy = "Id descending";
            return Filter(exp).OrderBy(orderBy).Skip(pageSize * (pageIndex - 1)).Take(pageIndex).ToList();
        }

        public async Task<List<T>> GetListAsync(int pageIndex, int pageSize, string orderBy = "",
            Expression<Func<T, bool>> exp = null)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (string.IsNullOrEmpty(orderBy))
                orderBy = "Id descending";
            return await Filter(exp).OrderBy(orderBy).Skip(pageSize * (pageIndex - 1)).Take(pageIndex).ToListAsync();
        }

        /// <summary>
        ///     根据过滤条件获取记录数
        /// </summary>
        public int GetCount(Expression<Func<T, bool>> exp = null)
        {
            return Filter(exp).Count();
        }

        /// <summary>
        ///     根据过滤条件获取记录数异步
        /// </summary>
        public async Task<int> GetCountAsync(Expression<Func<T, bool>> exp = null)
        {
            return await Filter(exp).CountAsync();
        }

        /// <summary>
        ///     根据过滤条件,判断是否存在
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public bool IsExist(Expression<Func<T, bool>> exp)
        {
            return _context.Set<T>().Any(exp);
        }

        /// <summary>
        ///     根据过滤条件,判断是否存在
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public async Task<bool> IsExistAsync(Expression<Func<T, bool>> exp)
        {
            return await _context.Set<T>().AnyAsync(exp);
        }

        #endregion

        #region 插入数据Insert,id要自己传，或者数据库中设置为自动标识+1

        /// <summary>
        ///     新增数据,不自动生成id
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool Insert(T entity, bool isSaveChange = true)
        {
            _context.Set<T>().Add(entity);
            if (isSaveChange) return _context.SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     新增数据,不自动生成id
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public async Task<bool> InsertAsync(T entity, bool isSaveChange = true)
        {
            _context.Set<T>().Add(entity);
            if (isSaveChange) return await _context.SaveChangesAsync() > 0;
            return false;
        }

        /// <summary>
        ///     批量，新增数据,不自动生成id
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool BatchInsert(T[] entities, bool isSaveChange = true)
        {
            _context.Set<T>().AddRange(entities);
            if (isSaveChange) return _context.SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     批量，新增数据,不自动生成id
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public async Task<bool> BatchInsertAsync(T[] entities, bool isSaveChange = true)
        {
            _context.Set<T>().AddRange(entities);
            if (isSaveChange) return await _context.SaveChangesAsync() > 0;
            return false;
        }

        #endregion

        #region 插入数据Add

        /// <summary>
        ///     新增数据,自动生成id
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool Add(T entity, bool isSaveChange = true)
        {
            entity.Id = Guid.NewGuid().ToString();
            _context.Set<T>().Add(entity);
            if (isSaveChange) return _context.SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     新增数据,自动生成id
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public async Task<bool> AddAsync(T entity, bool isSaveChange = true)
        {
            entity.Id = Guid.NewGuid().ToString();
            _context.Set<T>().Add(entity);
            if (isSaveChange) return await _context.SaveChangesAsync() > 0;
            return false;
        }

        /// <summary>
        ///     批量，新增数据,自动生成id
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool BatchAdd(T[] entities, bool isSaveChange = true)
        {
            foreach (var entity in entities) entity.Id = Guid.NewGuid().ToString();
            _context.Set<T>().AddRange(entities);
            if (isSaveChange) return _context.SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     批量，新增数据,自动生成id
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public async Task<bool> BatchAddAsync(T[] entities, bool isSaveChange = true)
        {
            foreach (var entity in entities) entity.Id = Guid.NewGuid().ToString();
            _context.Set<T>().AddRange(entities);
            if (isSaveChange) return await _context.SaveChangesAsync() > 0;
            return false;
        }

        #endregion

        #region 删除

        /// <summary>
        ///     根据id删除一行，不存在的返回false
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool DeleteById(string id, bool isSaveChange = true)
        {
            //var entity = _dbSet.SingleOrDefault(x => x.Id == id);
            //if (entity == null) return false;
            _dbSet.Remove(new T() { Id = id });
            return isSaveChange && SaveChanges() > 0;
        }

        /// <summary>
        ///     根据id删除一行，不查询直接删除
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isSaveChange"></param>
        public async Task<bool> DeleteByIdAsync(string id, bool isSaveChange = true)
        {
            //var entity = _dbSet.SingleOrDefault(x => x.Id == id);
            //if (entity == null) return false;
            _dbSet.Remove(new T(){Id=id});
            return isSaveChange && await SaveChangesAsync() > 0;
        }

        /// <summary>
        ///     根据实体删除单个实体
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool Delete(T entity, bool isSaveChange = true)
        {
            _dbSet.Attach(entity);
            _dbSet.Remove(entity);
            return isSaveChange && SaveChanges() > 0;
        }

        /// <summary>
        ///     根据实体列表批量删除
        /// </summary>
        /// <param name="entitis"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool Delete(List<T> entitis, bool isSaveChange = true)
        {
            entitis.ForEach(entity =>
            {
                _dbSet.Attach(entity);
                _dbSet.Remove(entity);
            });
            return isSaveChange && SaveChanges() > 0;
        }

        /// <summary>
        ///     根据实体删除单个实体
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteAsync(T entity, bool isSaveChange = true)
        {
            _dbSet.Attach(entity);
            _dbSet.Remove(entity);
            return isSaveChange && await SaveChangesAsync() > 0;
        }

        /// <summary>
        ///     根据实体列表批量删除,异步
        /// </summary>
        /// <param name="entitis"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteAsync(List<T> entitis, bool isSaveChange = true)
        {
            entitis.ForEach(entity =>
            {
                _dbSet.Attach(entity);
                _dbSet.Remove(entity);
            });
            return isSaveChange && await SaveChangesAsync() > 0;
        }

        /// <summary>
        ///     根据条件删除批量数据，无监控日志，
        /// </summary>
        /// <param name="exp"></param>
        public virtual void Delete(Expression<Func<T, bool>> exp)
        {
            _context.Set<T>().Where(exp).Delete();
        }

        #endregion

        #region 更新数据

        /// <summary>
        ///     根据实体更新数据,默认全字段更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <param name="updatePropertyList"></param>
        /// <returns></returns>
        public bool Update(T entity, bool isSaveChange = true, List<string> updatePropertyList = null)
        {
            if (entity == null) return false;
            _dbSet.Attach(entity);
            var entry = _context.Entry(entity);
            if (updatePropertyList == null)
                entry.State = EntityState.Modified;
            else
                updatePropertyList.ForEach(c => { entry.Property(c).IsModified = true; });
            if (isSaveChange) return SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     根据实体列表更新数据,默认全字段更新
        /// </summary>
        /// <param name="entitis"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public bool Update(List<T> entitis, bool isSaveChange = true)
        {
            if (entitis == null || entitis.Count == 0) return false;
            entitis.ForEach(c => { Update(c, false); });
            if (isSaveChange) return SaveChanges() > 0;
            return false;
        }

        /// <summary>
        ///     根据实体更新数据,默认全字段更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSaveChange"></param>
        /// <param name="updatePropertyList"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(T entity, bool isSaveChange = true, List<string> updatePropertyList = null)
        {
            if (entity == null) return false;
            _dbSet.Attach(entity);
            var entry = _context.Entry(entity);
            if (updatePropertyList == null)
                entry.State = EntityState.Modified; //全字段更新
            else
                updatePropertyList.ForEach(c => { entry.Property(c).IsModified = true; });
            if (isSaveChange) return await SaveChangesAsync() > 0;
            return false;
        }

        /// <summary>
        ///     根据实体列表更新数据,默认全字段更新
        /// </summary>
        /// <param name="entitis"></param>
        /// <param name="isSaveChange"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(List<T> entitis, bool isSaveChange = true)
        {
            if (entitis == null || entitis.Count == 0) return false;
            entitis.ForEach(c =>
            {
                _dbSet.Attach(c);
                _context.Entry(c).State = EntityState.Modified;
            });
            if (isSaveChange) return await SaveChangesAsync() > 0;
            return false;
        }


        /// <summary>
        ///     根据条件批量更新实体，实现按需要只更新部分更新，无更新日志，无原子事务
        ///     <para>如：Update(u =>u.Id==1,u =>new User{Name="ok"});</para>
        /// </summary>
        /// <param name="where">The where.</param>
        /// <param name="entity">The entity.</param>
        public void UpdatePart(Expression<Func<T, bool>> where, Expression<Func<T, T>> entity)
        {
            _context.Set<T>().Where(where).Update(entity);
        }

        #endregion

        #region 其他

        /// <summary>
        ///     根据sql执行语句
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public int ExecuteSql(string sql)
        {
            return _context.Database.ExecuteSqlCommand(sql);
        }

        /// <summary>
        ///     请在多表原子事务时调用
        /// </summary>
        /// <returns></returns>
        public int SaveChanges()
        {
            return _context.SaveChanges();
        }

        /// <summary>
        ///     请在多表原子事务时调用
        /// </summary>
        /// <returns></returns>
        public async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }

        #endregion
    }
}